/**
 * 用户表模型（对应数据库 user 表）
 * 功能整合：
 * 1. 基础字段定义（与数据库 user 表完全映射）
 * 2. 密码加密（bcrypt 加盐哈希,防止明文存储）
 * 3. 数据验证（用户名/密码非空、长度校验）
 * 4. 钩子函数（创建/更新前自动处理密码加密）
 * 5. 实例方法（登录时验证密码正确性）
 */

// 导入 Sequelize 的数据类型模块，用于定义模型字段类型
const { DataTypes } = require("sequelize");
// 导入密码加密工具
const bcrypt = require("bcryptjs");
// 导入数据库连接实例（已配置好的 Sequelize 连接）
const sequelize = require("../config/db");

// 定义 User 模型（映射数据库 user 表）
const User = sequelize.define(
  "User", // Sequelize 内部模型名（大写开头,约定俗成）
  {
    userId: {
      type: DataTypes.INTEGER, // 整数类型
      primaryKey: true, // 设为主键
      autoIncrement: true, // 自动递增
      allowNull: false, // 非空
      field: "user_id", // 映射数据库中的字段名(下划线命名)
      comment: "用户ID,主键（自增）,系统用户唯一标识", // 字段注释
    },
    username: {
      type: DataTypes.STRING(50), // 字符串类型，最大长度 50
      allowNull: false, // 非空
      unique: true, // 唯一索引（避免重复账号）
      validate: {
        notEmpty: { msg: "用户名不能为空" }, // 禁止纯空字符串
        len: { args: [2, 50], msg: "用户名长度必须在2-50个字符之间" }, // 长度约束
      },
      comment: "用户登录账号（唯一,支持2-50个字符）", // 字段注释
    },
    password: {
      type: DataTypes.STRING(100), // 字符串类型，最大长度 100
      allowNull: false, // 非空
      validate: {
        notEmpty: { msg: "密码不能为空" }, // 禁止纯空字符串
        len: { args: [5, 30], msg: "原始密码长度必须在5-30个字符之间" }, // 长度约束
      },
      comment: "用户密码（存储 bcrypt 加密后的哈希值,原始密码长度5-30字符）", // 字段注释
    },
  },
  {
    // 表配置
    tableName: "user", // 显式指定数据库表名（小写,与表名一致）
    freezeTableName: true, // 禁止 Sequelize 自动将表名复数化
    timestamps: true, // 启用自动时间戳（生成创建/更新时间）
    createdAt: "create_time", // 映射数据库 create_time 字段（创建时间）
    updatedAt: "update_time", // 映射数据库 update_time 字段（更新时间）
    comment: "用户表",
    // 定义表索引(优化查询性能)
    indexes: [
      {
        name: "uk_username", // 索引名（与数据库一致）
        fields: ["username"], //索引字段
        unique: true, // 唯一索引（避免重复账号）
      },
    ],
    // 钩子函数（生命周期回调,处理密码加密）
    hooks: {
      /**
       * 创建用户前执行：加密原始密码
       * @param {Object} user - 待创建的用户实例（包含前端传入的 username/password）
       */
      beforeCreate: async (user) => {
        if (user.password) {
          // 仅当密码存在时加密（避免空值异常）
          const salt = await bcrypt.genSalt(10); // 生成加密盐（复杂度10,平衡安全与性能）
          user.password = await bcrypt.hash(user.password, salt); // 盐+密码哈希
        }
      },
      /**
       * 更新用户前执行：若密码被修改,重新加密
       * @param {Object} user - 待更新的用户实例
       */
      beforeUpdate: async (user) => {
        // changed("password")：判断 password 字段是否被修改（避免无必要的加密）
        if (user.changed("password")) {
          const salt = await bcrypt.genSalt(10);
          user.password = await bcrypt.hash(user.password, salt);
        }
      },
    },
  }
);

// 实例方法：验证密码（登录时对比明文密码与加密密码）
/**
 * 验证前端传入的明文密码是否与数据库加密密码匹配
 * @param {string} password - 前端登录时传入的明文密码
 * @returns {boolean} - 匹配返回 true,不匹配返回 false
 */
User.prototype.validatePassword = async function (password) {
  // bcrypt.compare：自动用存储的哈希值中的盐解密,对比明文密码
  return await bcrypt.compare(password, this.password);
};

// 导出 User 模型（供控制器、服务层调用,如用户注册、登录、权限校验）
module.exports = User;
